import datetime

from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from cryptography.fernet import Fernet
from meiduo.settings import SECRET_KEY
# Create your views here.

from utils.customEncryption import jiami
from django.views import View
from apps.users import models
from django.http import JsonResponse

from utils.views import LoginRequiredJSONMixin

class UsernameCountView(View):  # 判断用户名是否重复

    def get(self, request, username):
        # /usernames/<username>/count/
        # 1.拿到用户名
        # 2.给数据库校验是否重复
        count_num = models.User.objects.filter(username=username).count()
        # 3.给前端返回json
        return JsonResponse({'code': 0, 'count': count_num, 'errmsg': 'ok'})


class MobileCountView(View):  # 判断手机号是否被注册

    def get(self, request, mobile):
        # mobiles/<mobile>/count/
        count_num = models.User.objects.filter(mobile=mobile).count()
        return JsonResponse({'code': 0, 'count': count_num, 'errmsg': 'ok'})

import re
import json
from apps.users import models


class RegisterView(View):  # 注册功能实现

    def post(self, request):
        # 1.获取请求参数 Json-字典
        body_bytes = request.body
        body_str = body_bytes.decode()
        body_dict = json.loads(body_str)

        username = body_dict.get("username")  # username: 用户名
        password = body_dict.get("password")  # password: 密码
        password2 = body_dict.get("password2")  # password2: 密码2
        mobile = body_dict.get("mobile")  # mobile: 手机号
        sms_code = body_dict.get("sms_code")  # sms_code: 短信验证码
        allow = body_dict.get("allow")  # allow:协议
        # 2.参数校验
        if not all([username, password, password2, mobile, allow]):
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'})
        #     2.1 校验用户名是否符合要求
        if not re.match(r'[a-zA-Z0-9_\u4e00-\u9fa5]{5,20}', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名不符合要求'})
        #     2.2 校验密码和确认密码是否一致
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次密码不相同'})
        #     2.3 校验手机号是否符合要求
        if not re.match(r'1[345789]\d{9}', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号不符合要求'})
        #     2.4 短信验证码是否正确
        from django_redis import get_redis_connection
        redis_cli=get_redis_connection('imageCode') #获得redis连接
        redisCodeSms=redis_cli.get(mobile)
        if  redisCodeSms is None: #判断验证码是否过期
            return JsonResponse({'code':400,'errmsg':'验证码过期，请重新获取'})
        if redisCodeSms.decode() != sms_code: #exit判断验证码是否正确
            return JsonResponse({'code':400,'errmsg':'验证码不正确'})
        #     2.5 是否同意协议
        if not allow:
            return JsonResponse({'code': 400, 'errmsg': '请同意协议'})
        # 3.数据入库
        # 这里使用Django认证系统用户模型类提供的create_user()方法创建新的用户。
        # 这里create_user()方法中封装了set_password()方法加密密码。
        try:
            user_data=models.User.objects.create_user(username=username, password=password, mobile=mobile)
            #
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '注册失败'})

        # 4.状态保持
        # Django用户认证系统提供了login()方法
        # 封装了写入session的操作，帮助我们快速实现状态保持
        # login(请求体,用户信息（models对象）)
        login(request, user_data)
        response=JsonResponse({'code': 0, 'errmsg': '注册成功'})
        response.set_cookie('username',username)
        # 5.响应数据
        return response


class loginView(View):
    """用户登录"""

    def post(self,request):
        # 1.接受前端数据
        data=json.loads(request.body.decode())
        username=data.get('username')
        password=data.get('password')
        remembered=data.get('remembered')
        # 2.做数据校验
        if not all([username,password]):
            return JsonResponse({"code":400,'errmsg':'缺少参数'})
        # 3.验证用户名密码是否正确
        from django.contrib.auth import authenticate
        from apps.users import models
        if re.match(r'1[3-9]\d{9}',username):
            models.User.USERNAME_FIELD='mobile' #通过更改模型的USERNAME_FIELD参数 指定django根据哪一字段做用户登录校验
        else:
            models.User.USERNAME_FIELD = 'username'
        user=authenticate(username=username,password=password) #django给我们用户校验函数，用户存在密码正确返回数据，否则返回None
        if user is None:
            return JsonResponse({"code":400,'errmsg':'账号或密码错误'})
        # 4.session状态保持
        from django.contrib.auth import login
        login(request,user)
        # 5.判断是否记住密码（session保持时间）
        if remembered: #记住密码
            request.session.set_expiry(None) #None 默认保存2周
        else:#不记住密码
            request.session.set_expiry(0) #0 浏览器退出cookie销毁

        # 5.返回前端json
        response=JsonResponse({"code":0,'errmsg':'登录成功'})
        #设置cookie来显示前端用户的展示
        response.set_cookie('username',username)
        #设置用户id（加密）
        response.set_cookie('key',jiami(expires_in=60*60*12*14).encryption(user.id))
        from apps.carts.carts_utils import merge_cart_cookie_to_redis
        #合并购物车
        response =merge_cart_cookie_to_redis(request,user,response)
        return response


class logoutView(View):
    """用户退出"""

    def delete(self,request):
        # 1.去除用户保持
        logout(request)
        # 2.删除指定cookie
        response=JsonResponse({'code': 0, 'errmsg': '用户退出'})
        response.delete_cookie('username')
        # 3.返回json
        return response


class userCenterView(LoginRequiredJSONMixin,View):
    """用户中心"""
    def get(self,request):
        info_data={
            'username':request.user.username,
            'mobile':request.user.mobile,
            'email':request.user.email,
            'email_active':request.user.email_active
        }
        # info_data.username;用户名
        # info_data.mobile; 手机号
        # info_data.email; 邮箱
        # info_data.email_active; 邮箱是否绑定
        return JsonResponse({'code':0,'errmsg':'ok','info_data':info_data})


class SaveEmailView(LoginRequiredJSONMixin,View):
    """保存用户邮箱"""
    def put(self,request):
        # 1.拿到前端的邮箱
        import json
        email=json.loads(request.body.decode()).get('email')
        # 2.校验邮箱
        import re
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}',email):
            return JsonResponse({'code':400,'errmsg':'邮箱格式错误'})
        #3.发验证邮件给用户，用户验证邮箱
        token=request.user.id
        if token is None: #判断id是否存在
            return JsonResponse({'code':400,'errmsg':'参数错误'})
        #给token加密
        from utils import customEncryption
        token=customEncryption.encryption(token)
        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html' + '?token=' +token
        subject = "阿威小店邮箱验证"
        html_message = '<p>尊敬的用户您好！</p>' \
                       '<p>感谢您使用阿威小店。</p>' \
                       '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
                       '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)
        #异步发送邮件
        from celery_tasks.email.tasks import celeryEmail
        celeryEmail.delay(subject=subject,recipient=email,html_message=html_message)
        # 4.保存邮箱
        request.user.email=email
        request.user.save()

        # 5.返回json数据
        return JsonResponse({'code':0,'errmsg':'ok'})


class BindEmailView(View):
    """用户邮箱绑定"""
    def put(self,request):
        # 1.获得前端的token
        token=request.GET.get('token')
        # 2.给token解密，判断是否过期
        from utils.customEncryption import decrypt
        try:
            token=decrypt(token)
        except Exception:
            return JsonResponse({'code':400,'errmsg':'参数错误'})
        # 3.去数据库校验
        from apps.users import models
        try:
            user=models.User.objects.get(id=token)
        except Exception:
            return JsonResponse({'code': 400, 'errmsg': '用户错误'})
        else:
            # 4.修改数据库邮箱状态
            user.email_active=True
            user.save()
        # 5.返回json
        return JsonResponse({'code':0,'errmsg':'ok'})


class CreateAddressView(LoginRequiredJSONMixin,View):
    """新增收货地址"""
    def post(self,request):
        # 0.判断用户保存了几个地址，大于20个不在保存
        from apps.areas.models import Address
        num=Address.objects.filter(user=request.user.id,is_deleted=False).count()
        if num >20 :
            return JsonResponse({'code':400,'errmsg':'收货地址最多保存20个！'})
        # 1.接受前端的参数
        import json
        datas=json.loads(request.body.decode())
        receiver=datas.get('receiver')
        province_id=datas.get('province_id')
        city_id=datas.get('city_id')
        district_id=datas.get('district_id')
        place=datas.get('place')
        mobile=datas.get('mobile')
        tel=datas.get('tel')
        email=datas.get('email')
        # 2.验证参数
        from django import http
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')
        # 3.数据入库
        address=Address.objects.create(
            user=request.user,
            title=receiver,
            receiver=receiver,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email,
        )
        #user(没有带id)只能传对象，通过对象找id，district_id（带id）只能传值，不能传对象
        address_dict={
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 4.返回数据
        return JsonResponse({'code':400,'errmsg':'ok','address':address_dict})


class AddressView(LoginRequiredJSONMixin,View):
    """展示地址"""
    def get(self,request):
        # 1.找到指定用户，拿所有数据
        from apps.areas.models import Address

        datas=Address.objects.filter(user=request.user,is_deleted=False)
        # 2.格式化数据
        # 创建空的列表
        address_dict_list = []

        # 遍历
        for address in datas:
            address_dict={
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            if address.id == request.user.default_address_id:
                address_dict_list.insert(0,address_dict)
            else:
                address_dict_list.append(address_dict)



        # 3.返回请求
        return JsonResponse({'code':0,'errmsg':'ok','addresses':address_dict_list,'default_address_id':request.user.default_address_id,'limit':20})


class PutAddressesTitleView(LoginRequiredJSONMixin,View):
    """更改用户收货地址的别名"""
    def put(self,request,addresses_id):
        # 1 数据库设置用户地址别名
        from apps.areas.models import Address
        import json
        title=json.loads(request.body.decode()).get('title')
        Address.objects.filter(id=addresses_id).update(title=title)
        # 2 返回数据
        return JsonResponse({'code':0,'errmsg':'ok'})


class UpdateDestroyAddressView(LoginRequiredJSONMixin,View):
    """修改，删除收货地址"""
    def put(self,request,addresses_id):
        """修改地址"""
        # 1.接受前端数据
        import json
        datas = json.loads(request.body.decode())
        receiver = datas.get('receiver')
        province_id = datas.get('province_id')
        city_id = datas.get('city_id')
        district_id = datas.get('district_id')
        place = datas.get('place')
        mobile = datas.get('mobile')
        tel = datas.get('tel')
        email = datas.get('email')
        # 2.校验数据
        from django import http
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')
        # 3.查询到指定地址，修改地址
        from apps.areas.models import Address
        Address.objects.filter(id=addresses_id).update(
            user=request.user,
            receiver=receiver,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email,
        )

        # 4.返回数据
        address = Address.objects.get(id=addresses_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return JsonResponse({'code': 0, 'errmsg': 'ok','address':address_dict})

    def delete(self,request,addresses_id):
        """删除收货地址"""
        # 1.找到指定地址，删除
        from apps.areas.models import Address
        Address.objects.filter(id=addresses_id).update(is_deleted=True)
        # 2.返回数据
        return JsonResponse({'code':0,'errmsg':'ok'})


class DefaultAddressView(LoginRequiredJSONMixin,View):
    """设置用户的默认收货地址"""
    def put(self,request,addresses_id):
        request.user.default_address_id=addresses_id
        request.user.save()

        return JsonResponse({'code':0,'errmsg':'ok'})


class ChangePasswordView(LoginRequiredJSONMixin,View):
    """用户修改密码"""
    def put(self,request):
        # 1.前端接受数据
        import json
        datas=json.loads(request.body.decode())
        old_password=datas.get('old_password')
        new_password=datas.get('new_password')
        new_password2=datas.get('new_password2')
        # 2.校验数据
            # 校验参数是否为空
        if not all([old_password,new_password,new_password2]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
            # 校验新密码是否相同
        if new_password2!=new_password:
            return JsonResponse({'code': 400, 'errmsg': '两次密码不相同'})
            # 校验旧密码是否正确
        if not request.user.check_password(old_password):
            return JsonResponse({'code':400,'errmsg':'密码错误'})
            #校验密码长度
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,'errmsg': '密码最少8位,最长20位'})
        # 3.数据库更改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception:
            return JsonResponse({'code': 400, 'errmsg': '数据库错误！'})
        # 4去除状态保持
        logout(request)
        response=JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.delete_cookie('username')
        # 5返回json数据
        return response


class UserBrowseHistory(LoginRequiredJSONMixin,View):
    """用户浏览记录"""

    def post(self,request):
        """保存用户浏览记录数据"""
        # 1.拿到前端商品SKU编号数据
        import json
        sku_id=json.loads(request.body.decode()).get('sku_id')
        # 2.判断商品是否存在
        from apps.goods.models import SKU
        try:
            SKU.objects.get(id=sku_id)
        except Exception:
            return JsonResponse({'code':400,'errmsg':'商品不存在'})
        # 3.连接redis用有序集合保存商品id
        from django_redis import get_redis_connection
        cli=get_redis_connection('history')
        import time
        mytime=str(int(time.time()))
        cli.zrem('history_%s'% request.user.id,sku_id)
        cli.zadd('history_%s'% request.user.id,{sku_id:mytime})
        # 4.返回json数据
        return JsonResponse({'code':0,'errmsg':'ok'})

    def get(self,request):
        """查询用户浏览记录 """
        # 1.查询redis，获得商品id
        from django_redis import get_redis_connection
        cli=get_redis_connection('history')
        #zrevrange(name, start, end, withscores=False, score_cast_func=float)
        '''参数：
            name    redis的name
            start   有序集合索引起始位置
            end     有序集合索引结束位置
            desc    排序规则，默认按照分数从小到大排序
            withscores  是否获取元素的分数，默认只获取元素的值
            score_cast_func 对分数进行数据转换的函数'''
        sku_list=cli.zrevrange('history_%s'% request.user.id,0,-1)
        if len(sku_list)>5:
            sku_list=sku_list[:5]
        # 2.根据商品id查询mysql
        from apps.goods.models import SKU
        skus = []
        for value in sku_list:
            sku=SKU.objects.get(id=value.decode())
            # 3.格式化数据
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        # 4.返回json
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'skus': skus})


from apps.goods.models import GoodsComment,SKU
class UserComments(View):
    """我的评论列表"""
    def get(self,request):
        """查看评论"""
        try:
            user = jiami(expires_in=60 * 60 * 12 * 14).decrypt(request.GET.get('key'))
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        querset_list=GoodsComment.objects.filter(user_id=user)

        #序列化
        data=[]
        for queset in querset_list:
            sku = SKU.objects.get(id=queset.sku_id)
            if 'http' in str(sku.default_image):
                sku_img =str(sku.default_image)
            sku_img='http://192.168.182.5:8888/'+str(sku.default_image)
            data.append({'sku_id':queset.sku_id,
                         'id':queset.id,
                         'comment':queset.comment,
                         'sku_img':sku_img,
                         'time':queset.update_time.strftime("%Y-%m-%d %H:%M:%S"),
                         'order_id':queset.order_id,
                         'spu_id':queset.spu_id,
                         'sku_name':sku.name})

        return JsonResponse({'code':200,'status':'ok','data':data})

class userCommentPut(View):
    """修改评论，删除评论"""
    def put(self,request):
        """修改评论"""
        body=json.loads(request.body)
        try:
            user_id=jiami(expires_in=60 * 60 * 12 * 14).decrypt(body.get('key'))
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})
        comment_id=body.get('comment_id')
        comment=body.get('comment')

        try:
            GoodsComment.objects.filter(id=comment_id,user_id=user_id).update(comment=comment)
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        return JsonResponse({'code':200,'errmsg':'ok'})

    def delete(self,request):
        """删除评论"""
        try:
            user = jiami(expires_in=60 * 60 * 12 * 14).decrypt(request.GET.get('key'))
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        try:
            GoodsComment.objects.filter(id=request.GET.get('id'),user_id=user).delete()
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        return JsonResponse({'code':205,'errmsg':'删除成功'})

from apps.users.models import User
class UserFindPwd(View):
    """用户找回密码"""
    def post(self,request):
        json_data=json.loads(request.body)
        phone=json_data.get('mobile')
        pwd=json_data.get('password')
        sms_code=json_data.get('sms_code')
        #短信验证码是否正确
        from django_redis import get_redis_connection
        redis_cli=get_redis_connection('imageCode') #获得redis连接
        redisCodeSms=redis_cli.get(phone)
        if  redisCodeSms is None: #判断验证码是否过期
            return JsonResponse({'code':400,'errmsg':'验证码过期，请重新获取'})
        if redisCodeSms.decode() != sms_code: #exit判断验证码是否正确
            return JsonResponse({'code':400,'errmsg':'验证码不正确'})
        user=User.objects.get(mobile=phone)
        user.set_password(pwd)
        user.save()


        return JsonResponse({'code':0,'errmsg':'ok'})






















